// FilterCoder.h

#ifndef __FILTER_CODER_H
#define __FILTER_CODER_H

#include "Common/COM/ICoder.h"
#include "Common/COM/IPassword.h"

class ATL_NO_VTABLE CFilterCoder :
  public ICompressCoder,
  public ICompressSetInStream,
  public ISequentialInStream,
  public ICompressSetOutStream,
  public ISequentialOutStream,
  public IOutStreamFlush,

  #ifndef _NO_CRYPTO
  public ICryptoSetPassword,
  #endif
  #ifndef EXTRACT_ONLY
  public ICompressSetCoderProperties,
  public ICompressWriteCoderProperties,
  // public ICryptoResetSalt,
  public ICryptoResetInitVector,
  #endif
  public ICompressSetDecoderProperties2,
  public CComObjectRootEx<CComSingleThreadModel>  
{
protected:
  BYTE *_buffer;
  CComPtr<ISequentialInStream> _inStream;
  CComPtr<ISequentialOutStream> _outStream;
  UINT32 _bufferPos;
  UINT32 _convertedPosBegin;
  UINT32 _convertedPosEnd;
  bool _outSizeIsDefined;
  UINT64 _outSize;
  UINT64 _nowPos64;

  HRESULT Init()
  {
    _nowPos64 = 0;
    _outSizeIsDefined = false;
    return Filter->Init();
  }

  CComPtr<ICryptoSetPassword> _setPassword;
  #ifndef EXTRACT_ONLY
  CComPtr<ICompressSetCoderProperties> _SetCoderProperties;
  CComPtr<ICompressWriteCoderProperties> _writeCoderProperties;
  // CComPtr<ICryptoResetSalt> _CryptoResetSalt;
  CComPtr<ICryptoResetInitVector> _CryptoResetInitVector;
  #endif
  CComPtr<ICompressSetDecoderProperties2> _setDecoderProperties;
public:
  CComPtr<ICompressFilter> Filter;

  HRESULT WriteWithLimit(ISequentialOutStream *outStream, UINT32 size);

public:
 /* MY_QUERYINTERFACE_BEGIN2(ICompressCoder)
    MY_QUERYINTERFACE_ENTRY(ICompressSetInStream)
    MY_QUERYINTERFACE_ENTRY(ISequentialInStream)
    MY_QUERYINTERFACE_ENTRY(ICompressSetOutStream)
    MY_QUERYINTERFACE_ENTRY(ISequentialOutStream)
    MY_QUERYINTERFACE_ENTRY(IOutStreamFlush)

    #ifndef _NO_CRYPTO
    MY_QUERYINTERFACE_ENTRY_AG(ICryptoSetPassword, Filter, _setPassword)
    #endif

    #ifndef EXTRACT_ONLY
    MY_QUERYINTERFACE_ENTRY_AG(ICompressSetCoderProperties, Filter, _SetCoderProperties)
    MY_QUERYINTERFACE_ENTRY_AG(ICompressWriteCoderProperties, Filter, _writeCoderProperties)
    // MY_QUERYINTERFACE_ENTRY_AG(ICryptoResetSalt, Filter, _CryptoResetSalt)
    MY_QUERYINTERFACE_ENTRY_AG(ICryptoResetInitVector, Filter, _CryptoResetInitVector)
    #endif

    MY_QUERYINTERFACE_ENTRY_AG(ICompressSetDecoderProperties2, Filter, _setDecoderProperties)
  MY_QUERYINTERFACE_END
  MY_ADDREF_RELEASE */

  BEGIN_COM_MAP(CFilterCoder)
	  COM_INTERFACE_ENTRY(ICompressCoder)
	  COM_INTERFACE_ENTRY(ICompressSetInStream)
	  COM_INTERFACE_ENTRY(ISequentialInStream)
	  COM_INTERFACE_ENTRY(ICompressSetOutStream)
	  COM_INTERFACE_ENTRY(ISequentialOutStream)
	  COM_INTERFACE_ENTRY(IOutStreamFlush)
#ifndef _NO_CRYPTO
	  COM_INTERFACE_ENTRY_AGGREGATE(__uuidof(ICryptoSetPassword), Filter)
#endif

#ifndef EXTRACT_ONLY
	  COM_INTERFACE_ENTRY_AGGREGATE(__uuidof(ICompressSetCoderProperties), Filter)
	  COM_INTERFACE_ENTRY_AGGREGATE(__uuidof(ICompressWriteCoderProperties), Filter)
	  COM_INTERFACE_ENTRY_AGGREGATE(__uuidof(ICryptoResetInitVector), Filter)	  
#endif
	  COM_INTERFACE_ENTRY_AGGREGATE(__uuidof(ICompressSetDecoderProperties2), Filter)
	  
  END_COM_MAP()



  DECLARE_PROTECT_FINAL_CONSTRUCT()

  HRESULT FinalConstruct();

  void FinalRelease();

  STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
      const UINT64 *inSize, const UINT64 *outSize, ICompressProgressInfo *progress);
  STDMETHOD(ReleaseInStream)();
  STDMETHOD(SetInStream)(ISequentialInStream *inStream);
  STDMETHOD(Read)(void *data, UINT32 size, UINT32 *processedSize); 
  STDMETHOD(SetOutStream)(ISequentialOutStream *outStream);
  STDMETHOD(ReleaseOutStream)();
  STDMETHOD(Write)(const void *data, UINT32 size, UINT32 *processedSize);
  STDMETHOD(Flush)();

  #ifndef _NO_CRYPTO
  STDMETHOD(CryptoSetPassword)(const BYTE *data, UINT32 size);
  #endif
  #ifndef EXTRACT_ONLY
  STDMETHOD(SetCoderProperties)(const PROPID *propIDs,
      const PROPVARIANT *properties, UINT32 numProperties);
  STDMETHOD(WriteCoderProperties)(ISequentialOutStream *outStream);
  // STDMETHOD(ResetSalt)();
  STDMETHOD(ResetInitVector)();
  #endif
  STDMETHOD(SetDecoderProperties2)(const BYTE *data, UINT32 size);
};

class CInStreamReleaser
{
public:
  CFilterCoder *FilterCoder;
  CInStreamReleaser(): FilterCoder(0) {}
  ~CInStreamReleaser() { if (FilterCoder) FilterCoder->ReleaseInStream(); }
};

class COutStreamReleaser
{
public:
  CFilterCoder *FilterCoder;
  COutStreamReleaser(): FilterCoder(0) {}
  ~COutStreamReleaser() { if (FilterCoder) FilterCoder->ReleaseOutStream(); }
};

#endif
